const path = require("path");
const webpack = require("webpack");
const { Command } = require("commander");
const { execFile } = require("child_process");
let clientConfig = require("./config/webpack.client");
let ssrverConfig = require("./config/webpack.server");
let srcompiler = webpack(clientConfig.bundleConfig());
let sscompiler = webpack(ssrverConfig);
let crcompiler = webpack(clientConfig.clientConfig());

let runs = [
  {
    name: "Server Render",
    compiler: srcompiler,
  },
  {
    name: "Client Render",
    compiler: crcompiler,
  },
  {
    name: "Server Context",
    compiler: sscompiler,
  },
];

let program = new Command();
program.name("编译插件");
program.description("这个工具可以帮助你快速构建");

let buildCommand = program
  .command("build")
  .description("打包应用程序")
  .option("-w, --watch", "以监听模式运行")
  .action((args) => {
    let isWatch = args.watch;
    if (isWatch) {
      watchBuild();
    } else {
      build();
    }
  });

// Initialization command
program.action((args) => {
  if (Object.keys(args).length === 0) {
    program.help();
  }
});
program.parse();
console.log("compiling ...");

function build() {
  // Client processing
  runs.forEach((item) => {
    let compiler = item.compiler;
    compiler.run((err, stats) => {
      if (err || stats.hasErrors()) {
        stats.toString({
          colors: true,
        });
        return;
      }
      console.log(`[${item.name}] Ok`);
    });
  });
}

function watchBuild() {
  // Server processing
  let runContext = null;
  // Client processing
  runs.forEach((item) => {
    let compiler = item.compiler;
    compiler.watch(
      {
        aggregateTimeout: 300,
      },
      (err, stats) => {
        item.isInit = true;
        let initNum = runs.filter((item) => item.isInit).length;
        if (err) return console.log(err.stack);
        let statsJson = stats.toJson();
        statsJson.errors.forEach((error) => console.log(error.toString()));
        statsJson.warnings.forEach((warning) => console.log(warning));
        // 如果都启动完成则启动服务器
        if (initNum >= runs.length) {
          if (runContext) {
            runContext.kill();
          }
          runContext = runServer();
        }
        console.log(`[${item.name}] Ok`);
      }
    );
  });
}

function runServer() {
  let output = sscompiler.outputPath;
  let serverPath = path.resolve(output, "server.js");
  let child = execFile(process.execPath, [serverPath], {
    cwd: output,
  });
  child.stdout.on("data", (data) => {
    console.log(`[Server]: ${data}`);
  });
  child.stderr.on("data", (data) => {
    console.error(`[Server]: ${data}`);
  });
  return child;
}
